package com.aidex.biz.service.impl;

import com.aidex.biz.domain.DocType;
import com.aidex.biz.mapper.DocTypeMapper;
import com.aidex.biz.service.BaseTreeServiceImpl;
import com.aidex.biz.service.DocTypeService;
import com.aidex.common.annotation.DataScope;
import com.aidex.common.constant.Constants;
import com.aidex.common.constant.UserConstants;
import com.aidex.common.core.domain.BaseEntity;
import com.aidex.common.core.domain.TreeNode;
import com.aidex.common.core.domain.entity.SysRole;
import com.aidex.common.exception.BizException;
import com.aidex.common.utils.NumberUtils;
import com.aidex.common.utils.PinYin4JCn;
import com.aidex.common.utils.StringUtils;
import com.aidex.common.utils.uuid.IdUtils;
import com.aidex.system.common.SysErrorCode;
import com.aidex.system.mapper.SysRoleMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 文件类型管理 服务实现
 *
 * @author ruoyi
 */
@Service
public class DocTypeServiceImpl extends BaseTreeServiceImpl<DocTypeMapper, DocType> implements DocTypeService {

    @Autowired
    private SysRoleMapper roleMapper;

    private static final int ID_LIMIT = 500;
    /**
     * 新增保存文件类型信息
     *
     * @return 结果
     */
    @Override
    public boolean save(DocType docType) {
        checkDeptNameUnique(docType);
        DocType parentDocType = mapper.get(docType.getParentId());
        docType.setDeptPinyin(PinYin4JCn.getFullAndSimplePinYin(docType.getDeptName(),500));
        if (null != parentDocType || StringUtils.isNotBlank(docType.getId())) {
            //没有父节点或者当前数据有ID(编辑跟节点时)
            //新增
            if (StringUtils.isEmpty(docType.getId())) {
                // 如果父节点不为正常状态,则不允许新增子节点
                if (!UserConstants.DEPT_NORMAL.equals(parentDocType.getStatus())) {
                    throw new BizException(SysErrorCode.B_SYSDEPT_DeptAlreadyUnNormal, "文件类型停用，不允许新增子文件类型");
                }
                setTreeProperties(docType, null, Constants.OpType.insert);
                super.save(docType);
            } else {
                //编辑
                DocType oldDocType = mapper.get(docType);
                if (isMoveToSelfChildNode(docType, oldDocType)) {
                    throw new BizException(SysErrorCode.B_SYSDEPT_DeptMoveUnNormal, "非法移动，不允许将节点移动到自身或者子节点下");
                }
                List<DocType> updateChildList = new ArrayList<DocType>();
                if (docType.getParentId().equals(docType.getId())) {
                    throw new BizException(SysErrorCode.B_SYSDEPT_DeptIdNotEqualParentId, "修改文件类型失败，上级文件类型不能是自己");
                }
                if (StringUtils.equals(UserConstants.DEPT_DISABLE, docType.getStatus()) && mapper.selectNormalChildByParentIds(docType.getParentIds()) > 0) {
                    throw new BizException(SysErrorCode.B_SYSDEPT_DeptHasNormalChild, "该文件类型包含未停用的子文件类型，不允许标记为停用");
                }
                if("dept".equals(docType.getDeptType())){
                    //当修改类型为文件类型时需要判断当前节点下所有子孙节点中是否存在公司节点
//                    DocType checkDocType = docType;//避免对象引用
                    DocType checkDocType = new DocType();
                    checkDocType.setId(docType.getId());
                    checkDocType.setDeptType("company");
                    List<DocType> checkList = mapper.searchChildrenTypeByParentId(checkDocType);
                    if(!CollectionUtils.isEmpty(checkList)){
                        throw new BizException(SysErrorCode.B_SYSDEPT_NoAllowUpdateType);
                    }
                }
                if (isUpdateTreeProperties(docType, oldDocType)) {
                    setTreeProperties(docType, oldDocType, Constants.OpType.update);
                    updateChildList = updateChildTreeProperties(docType, oldDocType);
                    if (!CollectionUtils.isEmpty(updateChildList)) {
                        mapper.updateDeptChildren(updateChildList);
                    }
                }
                parentDocType = mapper.get(docType.getParentId());
                // 新的父节点变更为非叶子节点
                if (!Constants.TREE_ROOT.equals(docType.getParentId()) && parentDocType.getTreeLeaf().equals(Constants.TREE_LEAF_Y)) {
                    parentDocType.setTreeLeaf(Constants.TREE_LEAF_N);
                    super.save(parentDocType);
                }
                String oldParentId = oldDocType.getParentId();
                super.save(docType);
                // 判断原节点是否还有子节点，否则改为叶子节点
                if (!hasChildByDeptId(oldParentId)) {
                    DocType oldParentDocType = mapper.get(oldParentId);
                    oldParentDocType.setTreeLeaf(Constants.TREE_LEAF_Y);
                    super.save(oldParentDocType);
                }
            }
        } else {
            //新增根节点
            docType.setId(IdUtils.randomUUID());
            docType.setNewRecord(true);
            docType.setParentIds(docType.getId());
            // 设置当前树全路径排序
            Integer treeSort = docType.getTreeSort();
            String treeSorts = String.format("%06d", treeSort);
            docType.setTreeSorts(treeSorts);
            docType.setTreeLeaf(Constants.TREE_LEAF_Y);
            // 设置当前节点级别.
            docType.setTreeLevel(1);
            super.save(docType);
        }
        return Boolean.TRUE;
    }

    /**
     * 删除文件类型
     *
     * @param docType
     * @return
     */
    @Override
    public boolean remove(DocType docType) {
        docType = mapper.get(docType.getId());
        if (hasChildByDeptId(docType.getId())) {
            throw new BizException(SysErrorCode.B_SYSDEPT_DeptHasChildNotDelete, "该文件类型包含子文件类型，不允许删除");
        }
        if (checkDeptExistUser(docType.getId())) {
            throw new BizException(SysErrorCode.B_SYSDEPT_DeptHasUserNotDelete, "该文件类型包含用户，不允许删除");
        }
        //删除
        super.remove(docType);
        //判断当前父节点下还是否有子节点，如果没有，则需要把父节点置为叶子节点
        DocType parentDocType = mapper.get(docType.getParentId());
        if (findChildCountById(docType.getParentId()) == 0) {
            parentDocType.setTreeLeaf(Constants.TREE_LEAF_Y);
            super.save(parentDocType);
        }
        return Boolean.TRUE;
    }

    public Integer findChildCountById(String docTypeId) {
        DocType docType = new DocType();
        docType.setParentId(docTypeId);
        return mapper.findCount(docType);
    }

    /**
     * 查询最大排序号
     *
     * @param docType
     * @return
     */
    @Override
    public Integer findMaxSort(DocType docType) {
        return NumberUtils.nextOrder(mapper.findMaxSort(docType));
    }

    /**
     * 是否存在子节点
     *
     * @param docTypeId 文件类型ID
     * @return 结果
     */
    @Override
    public boolean hasChildByDeptId(String docTypeId) {
        int result = findChildCountById(docTypeId);
        return result > 0;
    }

    /**
     * 查询文件类型是否存在用户
     *
     * @param deptId 文件类型ID
     * @return 结果 true 存在 false 不存在
     */
    @Override
    public boolean checkDeptExistUser(String deptId) {
        int result = mapper.checkDeptExistUser(deptId);
        return result > 0;
    }

    /**
     * 校验文件类型名称是否唯一
     *
     * @param dept 文件类型信息
     * @return 结果
     */
    @Override
    public void checkDeptNameUnique(DocType dept) {
        DocType docTypeUnique = new DocType();
        docTypeUnique.setNotEqualId(dept.getId());
        docTypeUnique.setDeptName(dept.getDeptName());
        docTypeUnique.setParentId(dept.getParentId());
        if (!CollectionUtils.isEmpty(mapper.findListWithUnique(docTypeUnique))) {
            throw new BizException(SysErrorCode.B_SYSDEPT_DeptNameAlreadyExist, "文件类型名称已经存在");
        }
    }

    /**
     * 根据展开层级和父节点递归获取展示的数据
     *
     * @param level
     * @param parentId
     * @return
     */
    @Override
    @DataScope(deptAlias = "t",userAlias = "t")
    public List<DocType> listDataByLevel(DocType docType,int level, String parentId) {
        List<DocType> listData = new ArrayList<DocType>();
        level--;
        List<DocType> childrenList = findChildListByParentId(parentId,docType);
        for (DocType dto : childrenList) {
            if ("n".equals(dto.getTreeLeaf()) && level > 0) {
                dto.setChildren(this.listDataByLevel(docType,level, dto.getId()));
            } else {
                dto.setChildren(new ArrayList<>());
            }
            listData.add(dto);
        }
        return listData;
    }

    /**
     * 根据角色ID查询文件类型树信息
     *
     * @param roleId 角色ID
     * @return 选中文件类型列表
     */
    @Override
    public List<Integer> selectDeptListByRoleId(String roleId) {
        SysRole role = roleMapper.get(roleId);
        return mapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
    }

    /**
     * 构建前端所需要树结构
     *
     * @param level    展开层级
     * @param parentId 父节点ID
     * @return
     */
    @Override
    @DataScope(deptAlias = "t",userAlias = "t")
    public List<TreeNode> buildDeptTree(DocType docType,int level, String parentId) {
        return this.buildDeptTreeExcludeChild(docType,level, parentId, "");
    }

    /**
     * 构建前端所需要树结构
     *
     * @param level     展开层级
     * @param parentId  父节点ID
     * @param excludeId 排除节点ID
     * @return
     */
    @Override
    public List<TreeNode> buildDeptTreeExcludeChild(DocType dept,int level, String parentId, String excludeId) {
        List<TreeNode> listData = new ArrayList<TreeNode>();
        level--;
        List<DocType> childrenList = findChildListByParentId(parentId,dept);
        for (DocType docType : childrenList) {
            if (!docType.getId().equals(excludeId)) {
                TreeNode treeNode = this.transToTreeNodeData(docType);
                if ("n".equals(docType.getTreeLeaf()) && level != 0) {
                    treeNode.setChildren(this.buildDeptTreeExcludeChild(dept,level, docType.getId(), excludeId));
                } else {
                    treeNode.setChildren(null);
                }
                //不展开节点的父节点数据处理
                if (CollectionUtils.isEmpty(treeNode.getChildren())) {
                    treeNode.setChildren(null);
                }
                listData.add(treeNode);
            }
        }
        return listData;
    }
    /**
     * 树表格检索
     *
     * @param queryParams    检索对象
     * @return
     */
    @Override
    public List<DocType> searchDeptList(DocType queryParams){
        List<DocType> docTypeList = new ArrayList<DocType>();
        List<DocType> searchNodes = mapper.searchDocTypeTree(queryParams);
        if (!CollectionUtils.isEmpty(searchNodes)){
            Set<String> treeIdSet = reDuplicationByTreePath(searchNodes);
            int i = 0;
            //考虑mybatis foreach的限制，所以定义参数格式为list内还是list
            List<List<String>> idsList = new ArrayList<List<String>>();
            List<String> idList = new ArrayList<String>();
            for (String treeId : treeIdSet) {
                //当id个数超出限制后，则新new一个list来存放
                if(i % ID_LIMIT == 0 && i > 0){
                    idsList.add(idList);
                    idList = new ArrayList<String>();
                }
                idList.add(treeId);
                i++;
            }
            idsList.add(idList);
            List<DocType> allNodes = mapper.searchDocTypeTreeByIds(idsList);
            docTypeList = createTreeGridData(allNodes);
        }
        return docTypeList;
    }
    /**
     *  组建树形结构
     * @param entityNodes 节点集合
     * @return List<VueNode>
     */
    private List<DocType> createTreeGridData(List<DocType> entityNodes) {
        List<DocType> treeList = new ArrayList<DocType>();
        for (DocType docType : entityNodes) {
            //找到根节点
            if (Constants.TREE_ROOT.equals(docType.getParentId())) {
                treeList.add(docType);
            }
            List<DocType> children = new ArrayList<DocType>();
            //再次遍历list，找到子节点
            for (DocType node : entityNodes) {
                if (node.getParentId().equals(docType.getId())) {
                    children.add(node);
                }
            }
            docType.setChildren(children);
            if (children.isEmpty()){
                docType.setTreeLeaf("y");
            }else{
                docType.setTreeLeaf("n");
            }
        }
        return treeList;
    }
    /**
     * 检索树
     * @param searchText    检索字符
     * @return
     */
    @Override
    public List<TreeNode> search(String searchText){
        List<TreeNode> tree = new ArrayList<TreeNode>();
        DocType queryParams = new DocType();
        queryParams.setSearchText(searchText);
        List<DocType> searchNodes = mapper.searchDocTypeTree(queryParams);
        if (!CollectionUtils.isEmpty(searchNodes)){
            Set<String> treeIdSet = reDuplicationByTreePath(searchNodes);
            int i = 0;
            //考虑mybatis foreach的限制，所以定义参数格式为list内还是list
            List<List<String>> idsList = new ArrayList<List<String>>();
            List<String> idList = new ArrayList<String>();
            for (String treeId : treeIdSet) {
                //当id个数超出限制后，则新new一个list来存放
                if(i % ID_LIMIT == 0 && i > 0){
                    idsList.add(idList);
                    idList = new ArrayList<String>();
                }
                idList.add(treeId);
                i++;
            }
            idsList.add(idList);
            List<DocType> allNodes = mapper.searchDocTypeTreeByIds(idsList);
            tree = createTreeData(allNodes);
        }
        return tree;
    }
    /**
     * 根据parentIds去重
     * @param entityNodes entityNodes
     */
    private Set<String> reDuplicationByTreePath(List<DocType> entityNodes) {
        Set<String> treeIdSet = new HashSet<String>();
        for (DocType dto : entityNodes) {
            String treePath = dto.getParentIds();
            treeIdSet.addAll(Arrays.asList(treePath.split("/")));
        }
        return treeIdSet;
    }
    /**
     *  组建树形结构
     * @param entityNodes 节点集合
     * @return List<VueNode>
     */
    private List<TreeNode> createTreeData(List<DocType> entityNodes) {
        List<TreeNode> list = transToTreeNodeData(entityNodes);
        List<TreeNode> tree = new ArrayList<TreeNode>();
        for (TreeNode treeNode : list) {
            //找到根节点
            if (Constants.TREE_ROOT.equals(treeNode.getParentId())) {
                tree.add(treeNode);
            }
            List<TreeNode> children = new ArrayList<TreeNode>();
            //再次遍历list，找到子节点
            for (TreeNode node : list) {
                if (node.getParentId().equals(treeNode.getId())) {
                    children.add(node);
                }
            }
            treeNode.setChildren(children);
            if (children.isEmpty()){
                treeNode.setIsLeaf(true);
            }
        }
        return tree;
    }
    /**
     *  将实体类集合转化成VueNode格式
     * @param entityNodes  实体类节点集合
     * @return List<VueNode>
     */
    private List<TreeNode> transToTreeNodeData(List<DocType> entityNodes) {
        List<TreeNode> treeNodes = new ArrayList<TreeNode>();
        for (DocType entityNode : entityNodes) {
            TreeNode treeNode = transToTreeNodeData(entityNode);
            treeNodes.add(treeNode);
        }
        return treeNodes;
    }
    /**
     *  将实体类转化成VueNode格式
     * @param entityNode  实体类节点集合
     * @return List<VueNode>
     */
    private TreeNode transToTreeNodeData(DocType entityNode) {
        TreeNode treeNode = new TreeNode();
        treeNode.setId(entityNode.getId());
        treeNode.setKey(entityNode.getId());
        treeNode.setTitle(entityNode.getDeptName());
        treeNode.setLabel(entityNode.getDeptName());
        treeNode.setSelectable(true);
        treeNode.setDisabled(false);
        treeNode.setDisableCheckbox(false);
        treeNode.setParentId(entityNode.getParentId());
        treeNode.setParentIds(entityNode.getParentIds());
        HashMap<String,Object> attr = new HashMap<>();
        attr.put("treeLeaf", entityNode.getTreeLeaf());
        attr.put("treeLevel", entityNode.getTreeLevel());
        attr.put("treePath", entityNode.getParentIds());
        attr.put("deptType", entityNode.getDeptType());
        attr.put("subtitle", entityNode.getSubtitle());
        attr.put("deptPinyin", entityNode.getDeptPinyin());
        treeNode.setAttributes(attr);
        if (Constants.TREE_LEAF_Y.equals(entityNode.getTreeLeaf())){
            treeNode.setIsLeaf(true);
        } else{
            treeNode.setIsLeaf(false);
        }
        JSONObject slotsValue = new JSONObject();
        String deptType = StringUtils.isNotBlank(entityNode.getDeptType()) ? entityNode.getDeptType() : "";
        if ("org".equals(deptType)) {
            slotsValue.put("icon", "org");
            treeNode.setDisableCheckbox(true);
        } else if ("company".equals(deptType)) {
            slotsValue.put("icon", "company");
            treeNode.setDisableCheckbox(true);
        } else if ("dept".equals(deptType)) {
            slotsValue.put("icon", "dept");
            treeNode.setDisableCheckbox(false);
        } else if ("user".equals(deptType)) {
            slotsValue.put("icon", "user");
            treeNode.setDisableCheckbox(false);
        }
        JSONObject scopedSlotsValue = new JSONObject();
        scopedSlotsValue.put("title","title");
        scopedSlotsValue.put("attributes","attributes");
        treeNode.setSlots(slotsValue);
        treeNode.setScopedSlots(scopedSlotsValue);
        return treeNode;
    }

    /**
     * 构建前端所需要树结构
     *
     * @param level    展开层级
     * @param parentId 父节点ID
     * @return
     */
    @Override
    public List<TreeNode> buildDeptSelectUserTree(int level, String parentId) {
        List<TreeNode> listData = new ArrayList<TreeNode>();
        level--;
        DocType queryDocType = new DocType();
        queryDocType.setParentId(parentId);
        List<DocType> childrenList = mapper.findDeptAndUserChildListByParentId(queryDocType);
        for (DocType docType : childrenList) {
                TreeNode treeNode = this.transToTreeNodeData(docType);
                if ("n".equals(docType.getTreeLeaf())  && level > 0) {
                    treeNode.setChildren(this.buildDeptSelectUserTree(level, docType.getId()));
                } else {
                    treeNode.setChildren(null);
                }
                //不展开节点的父节点数据处理
                if (CollectionUtils.isEmpty(treeNode.getChildren())) {
                    treeNode.setChildren(null);
                }
                listData.add(treeNode);
        }
        return listData;
    }
    /**
     * 按文件类型检索用户
     * @param docType    检索字符
     * @return
     */
    @Override
    public List<TreeNode> searchDeptUserList(DocType docType){
        List<TreeNode> tree = new ArrayList<TreeNode>();
        DocType queryParams = new DocType();
        queryParams.setSearchText(docType.getSearchText());
        List<DocType> searchNodes = mapper.searchDocTypeUserTree(queryParams);
        if (!CollectionUtils.isEmpty(searchNodes)){
            Set<String> treeIdSet = reDuplicationByTreePath(searchNodes);
            int i = 0;
            //考虑mybatis foreach的限制，所以定义参数格式为list内还是list
            List<List<String>> idsList = new ArrayList<List<String>>();
            List<String> idList = new ArrayList<String>();
            for (String treeId : treeIdSet) {
                //当id个数超出限制后，则新new一个list来存放
                if(i % ID_LIMIT == 0 && i > 0){
                    idsList.add(idList);
                    idList = new ArrayList<String>();
                }
                idList.add(treeId);
                i++;
            }
            idsList.add(idList);
            List<DocType> allNodes = mapper.searchDocTypeUserTreeByIds(idsList);
            tree = createTreeData(allNodes);
        }
        return tree;
    }

    @Override
    public List<Map<String,Object>> getDeptInfoByIds(JSONObject deptIdsObj){
        String[] deptIds = deptIdsObj.getString("deptIds").split(";");
        int i = 0;
        //考虑mybatis foreach的限制，所以定义参数格式为list内还是list
        List<List<String>> idsList = new ArrayList<List<String>>();
        List<String> idList = new ArrayList<String>();
        for (String deptId : deptIds) {
            //当id个数超出限制后，则新new一个list来存放
            if(i % 500 == 0 && i > 0){
                idsList.add(idList);
                idList = new ArrayList<String>();
            }
            idList.add(deptId);
            i++;
        }
        idsList.add(idList);
        return mapper.getDeptInfoByIds(idsList);
    }


    /**
     * 通过文件类型编码查询文件类型
     *
     * @param deptCode 文件类型编码
     * @return 文件类型对象信息
     */
    @Override
    public DocType selectDeptByDeptCode(String deptCode)
    {
        return mapper.selectDeptByDeptCode(deptCode, BaseEntity.DEL_FLAG_NORMAL);
    }
}
